{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这一章，没啥好记录的。\n",
    "\n",
    "关于网络与web编程，学了不用是白搭，用的多了自然就熟练了。\n",
    "\n",
    "读一遍，走个过场。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.作为客户端与HTTP服务交互\n",
    "\n",
    "- urllib.\n",
    "  - request\n",
    "  - parse\n",
    "- requests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.创建TCP服务器\n",
    "\n",
    "- socketserver.\n",
    "  - BaseRequestHandler\n",
    "  - StreamRequestHandler\n",
    "  - ThreadingTCPServer\n",
    "  - ForkingTCPServer \n",
    "  - TCPServer\n",
    "- socket.\n",
    "  - socket\n",
    "  - AF_INET\n",
    "  - SOCK_STREAM"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.创建UDP服务器\n",
    "\n",
    "- socketserver.\n",
    "  - BaseRequestHandler\n",
    "  - UDPServer\n",
    "  - ForkingUDPServer\n",
    "  - ThreadingUDPServer\n",
    "- socket.\n",
    "  - socket\n",
    "  - AF_INET\n",
    "  - SOCK_DGRAM"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.通过CIDR地址生成对应的IP地址集\n",
    "\n",
    "- ipaddress 模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.创建一个简单的REST接口\n",
    "\n",
    "跳过。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.通过XML-RPC实现简单的远程调用\n",
    "\n",
    "你想找到一个简单的方式去执行运行在远程机器上面的Python程序中的函数或方法。\n",
    "\n",
    "- xmlrpc.server.\n",
    "  - SimpleXMLRPCServer\n",
    "- xmlrpc.client.\n",
    "  - ServerProxy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7.在不同的Python解释器之间交互\n",
    "\n",
    "你在不同的机器上面运行着多个Python解释器实例，并希望能够在这些解释器之间通过消息来交换数据。\n",
    "\n",
    "通过使用 multiprocessing.connection 模块可以很容易的实现解释器之间的通信。\n",
    "\n",
    "一个通用准则是，你不要使用 multiprocessing 来实现一个对外的公共服务。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8.实现远程方法调用\n",
    "\n",
    "你想在一个消息传输层如 sockets 、multiprocessing connections 或 ZeroMQ 的基础之上实现一个简单的远程过程调用（RPC）。\n",
    "\n",
    "将函数请求、参数和返回值使用pickle编码后，在不同的解释器直接传送pickle字节字符串，可以很容易的实现RPC。\n",
    "\n",
    "> 太麻烦了，不如直接使用RPC框架"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.简单的客户端认证\n",
    "\n",
    "你想在分布式系统中实现一个简单的客户端连接认证功能，又不想像SSL那样的复杂。\n",
    "\n",
    "可以利用 hmac 模块实现一个连接握手，从而实现一个简单而高效的认证过程。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10.在网络服务中加入SSL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# server端\n",
    "from socket import socket, AF_INET, SOCK_STREAM\n",
    "import ssl\n",
    "\n",
    "KEYFILE = 'server_key.pem'   # Private key of the server\n",
    "CERTFILE = 'server_cert.pem' # Server certificate (given to client)\n",
    "\n",
    "def echo_client(s):\n",
    "    while True:\n",
    "        data = s.recv(8192)\n",
    "        if data == b'':\n",
    "            break\n",
    "        s.send(data)\n",
    "    s.close()\n",
    "    print('Connection closed')\n",
    "\n",
    "def echo_server(address):\n",
    "    s = socket(AF_INET, SOCK_STREAM)\n",
    "    s.bind(address)\n",
    "    s.listen(1)\n",
    "\n",
    "    # Wrap with an SSL layer requiring client certs\n",
    "    s_ssl = ssl.wrap_socket(s,\n",
    "                            keyfile=KEYFILE,\n",
    "                            certfile=CERTFILE,\n",
    "                            server_side=True\n",
    "                            )\n",
    "    # Wait for connections\n",
    "    while True:\n",
    "        try:\n",
    "            c,a = s_ssl.accept()\n",
    "            print('Got connection', c, a)\n",
    "            echo_client(c)\n",
    "        except Exception as e:\n",
    "            print('{}: {}'.format(e.__class__.__name__, e))\n",
    "\n",
    "echo_server(('', 20000))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "客户端\n",
    "\n",
    "```\n",
    ">>> from socket import socket, AF_INET, SOCK_STREAM\n",
    ">>> import ssl\n",
    ">>> s = socket(AF_INET, SOCK_STREAM)\n",
    ">>> s_ssl = ssl.wrap_socket(s,\n",
    "                cert_reqs=ssl.CERT_REQUIRED,\n",
    "                ca_certs = 'server_cert.pem')\n",
    ">>> s_ssl.connect(('localhost', 20000))\n",
    ">>> s_ssl.send(b'Hello World?')\n",
    "12\n",
    ">>> s_ssl.recv(8192)\n",
    "b'Hello World?'\n",
    ">>>\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11.进程间传递Socket文件描述符\n",
    "\n",
    "为了在多个进程中传递文件描述符，你首先需要将它们连接到一起。\n",
    "\n",
    "在Unix机器上，你可能需要使用Unix域套接字， 而在windows上面你需要使用命名管道。\n",
    "\n",
    "不过你无需真的需要去操作这些底层， 通常使用 multiprocessing 模块来创建这样的连接会更容易一些。\n",
    "\n",
    "一旦一个连接被创建，你可以使用 multiprocessing.reduction 中的 send_handle() 和 recv_handle() 函数在不同的处理器直接传递文件描述符。\n",
    "\n",
    "代码，没看懂。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 12.理解事件驱动的IO\n",
    "\n",
    "好复杂。\n",
    "\n",
    "还是使用一个通用的框架更好。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 13.发送与接收大型数组\n",
    "\n",
    "跳过。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.7 ('base')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "caf1c2fcf97217de91eafa76b907d50f9ea378f5ffbee7f571142d119bb6a771"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
